#pragma once

#include "../Sol9Types.h"

namespace sol9
{
namespace encoding
{

	class CEncodingBase;

	class CEncoding
	{
	private:
		class helper
		{
		private:
			typedef std::map<u32, CEncoding*> EncodingMap;
			EncodingMap encodings;

		public:
			helper();
			~helper();

			const CEncoding& getEncoding(u32 nCodePage);
		};

		static helper m_sHelper;
		CEncodingBase* m_pEncodingData;

	private:
		CEncoding();
		CEncoding(CEncodingBase* pEncodingBase);
		~CEncoding();

	public:
		static const CEncoding& Default();
		static const CEncoding& ASCII();
		static const CEncoding& UTF8();
		static const CEncoding& Unicode();
		static const CEncoding& UnicodeBigEndian();

		static const CEncoding& getEncoding(u32 nCodePage);
		static bool Convert(const CEncoding& srcEncoding, const CEncoding& dstEncoding, const std::vector<char>& input, std::vector<char>& output);
		static bool Convert(const CEncoding& srcEncoding, const CEncoding& dstEncoding, const std::string& input, std::string& output);
		static std::string Convert(const CEncoding& srcEncoding, const CEncoding& dstEncoding, const std::string& input);
		
		bool operator == ( const CEncoding& other ) const
		{
			return m_pEncodingData == other.m_pEncodingData;
		}

		bool operator != (const CEncoding& other) const
		{
			return m_pEncodingData != other.m_pEncodingData;
		}

		u32 getCharCount(const wchar_t* input, u32 count) const;
		u32 getCharCount(const wchar_t* input) const;
		u32 getCharCount(const std::vector<wchar_t>& input) const;
		u32 getCharCount(const std::wstring& input) const;

		void getChars(const wchar_t* input, u32 inputCount, char* output, u32 outputCount) const;
		void getChars(const std::vector<wchar_t>& input, std::vector<char>& output) const;
		void getChars(const std::wstring& input, std::vector<char>& output) const;
		std::vector<char> getChars(const wchar_t* input) const;
		std::vector<char> getChars(const std::vector<wchar_t>& input) const;
		std::vector<char> getChars(const std::wstring& input) const;

		void getStringA(const std::vector<wchar_t>& input, std::string& output) const;
		void getStringA(const std::wstring& input, std::string& output) const;
		std::string getStringA(const std::vector<wchar_t>& input) const;
		std::string getStringA(const std::wstring& input) const;

		u32 getWideCharCount(const char* input, u32 count) const;
		u32 getWideCharCount(const char* input) const;
		u32 getWideCharCount(const std::vector<char>& input) const;
		u32 getWideCharCount(const std::string& input) const;

		void getWideChars(const char* input, u32 inputCount, wchar_t* output, u32 outputCount) const;
		void getWideChars(const std::vector<char>& input, std::vector<wchar_t>& output) const;
		void getWideChars(const std::string& input, std::vector<wchar_t>& output) const;
		std::vector<wchar_t> getWideChars(const char* input) const;
		std::vector<wchar_t> getWideChars(const std::vector<char>& input) const;
		std::vector<wchar_t> getWideChars(const std::string& input) const;

		void getStringW(const std::vector<char>& input, std::wstring& output) const;
		void getStringW(const std::string& input, std::wstring& output) const;
		std::wstring getStringW(const std::vector<char>& input) const;
		std::wstring getStringW(const std::string& input) const;

		u32 getMaxCharCount(u32 inputCount) const;
		u32 getMaxWideCharCount(u32 inputCount) const;

		u32 getCharUnitSize(const char& input) const;

		u32 getCodePage() const;
		const std::wstring& getEncodingName() const;
		const std::vector<unsigned char>& getPreamble() const;

		const std::string& getSpaceToken() const;
		const std::string& getTabToken() const;
		const std::string& getCarriageReturnToken() const;
		const std::string& getNextLineToken() const;

		bool IsSingleByte() const;
		bool IsValid() const;
	};

} // namespace encoding
} // namespace sol9